package com.chuanye.cluster.message;

import com.chuanye.cluster.models.YY_DATA_AUTO_Request;
import com.chuanye.cluster.pojo.*;
import com.chuanye.cluster.utils.GsonUtils;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.lang.reflect.Array;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

@ServerEndpoint(value = "/devSignal")
@Component
public class DevSignalWebSocket {

    /**
     * 因为@ServerEndpoint不支持注入，所以使用SpringUtils获取IOC实例
     */
    //StringRedisTemplate stringRedisTemplate = SpringUtils.getBean(StringRedisTemplate.class);

    private static RedisUtils redisTampate;

    @Autowired
    private void setChatService(RedisUtils redisTampate) {
        DevSignalWebSocket.redisTampate = redisTampate;
    }

    private  static ServerConfig serverConfig=SpringUtils.getBean(ServerConfig.class);

    private static Logger log = LoggerFactory.getLogger(DevSignalWebSocket.class);
    private static final AtomicInteger OnlineCount = new AtomicInteger(0);
    private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
    private static CopyOnWriteArraySet<SocketMultipleRegisterDto>  socketBaseDtoSet = new CopyOnWriteArraySet<SocketMultipleRegisterDto>();
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session) {
        SessionSet.add(session);
        int cnt = OnlineCount.incrementAndGet(); // 在线数加1
        log.info("有连接加入，当前连接数为：{}", cnt);
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose(Session session) {
        SessionSet.remove(session);
        removeSessionBySessionId(session.getId());
        int cnt = OnlineCount.decrementAndGet();
        log.info("连接总数：{}", cnt);
    }

    /**
     * 收到客户端消息后调用的方法
     *
     * @param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            //接受消息并创建订阅对象
            SocketBaseDto baseDto = GsonUtils.fromJson(message, SocketBaseDto.class);
            //注册且订阅
            if (baseDto.getSocketType() == SocketEnum.registerAndSubscribe.getValue()) {
                //用户订阅
                SocketMultipleRegisterDto registerDto = GsonUtils.fromJson(message, SocketMultipleRegisterDto.class);
                //清理
                removeSessionByUserID(baseDto.getUserID());
                removeSessionBySessionId(session.getId());

                //放入本地用户在线集合
                registerDto.setSessionId(session.getId());
                socketBaseDtoSet.add(registerDto);
                String registerStr = GsonUtils.toJson(registerDto);
            }
            //正常转发
            else if (baseDto.getSocketType() == SocketEnum.send.getValue()) {
                //向用户发送
                SocketSendToUserDto sendtoUserDto = GsonUtils.fromJson(message, SocketSendToUserDto.class);
                if(sendtoUserDto.getTargetUserID()!=null && sendtoUserDto.getTargetUserID().equals("")!=true)
                {
                    redisTampate.convertAndSend("chat",message);
                }
            }
            else if(baseDto.getSocketType()==SocketEnum.userTotal.getValue()){
                String dataJson = GsonUtils.toJson(socketBaseDtoSet);
                SendMessage(session.getId(), dataJson);
            }
            //BroadCastInfo(message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    /**
     * 出现错误
     *
     * @param session
     * @param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误：{}，Session ID： {}", error.getMessage(), session.getId());
        error.printStackTrace();
    }

    /**
     *
     * @param session
     * @param message
     */
    public static void SendMessage(Session session, String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("发送消息出错：{}", e.getMessage());
            e.printStackTrace();
        }
    }


    /**
     * 群发消息
     *
     * @param message
     * @throws IOException
     */
    public static void BroadCastInfo(String message) throws IOException {
        for (Session session : SessionSet) {
            if (session.isOpen()) {
                SendMessage(session, message);
            }
        }
    }

    /**
     * 指定Session发送消息
     *
     * @param sessionId
     * @param message
     * @throws IOException
     */
    public static void SendMessage(String sessionId, String message) throws IOException {
        Session session = null;
        for (Session s : SessionSet) {
            if (s.getId().equals(sessionId)) {
                session = s;
                break;
            }
        }
        if (session != null) {
            SendMessage(session, message);
        } else {
            log.info("没有找到你指定ID的会话：{}", sessionId);
        }
    }




    /**
     * Redis用户Key生成规则
     *
     * @param  sessionID
     * @param  userID
     * @return key
     */
    public static String redisKeyRule(String sessionID, String userID) {
        try {
            if (sessionID==null || sessionID.equals("") || userID==null|| userID.equals("")) {
                return null;
            }
            InetAddress addr = InetAddress.getLocalHost();
            String key=addr.getHostAddress()+"_"+sessionID+"_"+userID;
            return key;
        } catch (Exception ex) {
            return null;
        }
    }




    /**
     * 通过 RedisConfig=>listenerAdapter 订阅方法用于发布
     * @param  message
     */
    public static void receiveMessage(String message) {
        try {
            SocketBaseDto baseDto = GsonUtils.fromJson(message, SocketBaseDto.class);
            if (baseDto.getSocketType() == SocketEnum.send.getValue()) {
                SocketSendToUserDto sendtoUserDto = GsonUtils.fromJson(message, SocketSendToUserDto.class);
                String sessionid = getSessionidByUserID(sendtoUserDto.getTargetUserID());
                if (sessionid != null) {
                    SendMessage(sessionid, sendtoUserDto.getMessage());
                }
            } else if (baseDto.getSocketType() == SocketEnum.sendAll.getValue()) {
                for (SocketMultipleRegisterDto s : socketBaseDtoSet) {
                    SendMessage(s.getSessionId(), message);
                }
            } else if (baseDto.getSocketType() == SocketEnum.push.getValue()) {
                //由第三方推送过来业务数据
                String prefix = DevSignalController.pushDataKey + "_*";
                Set<String> setKeys = redisTampate.keys(prefix);
                for (SocketMultipleRegisterDto s : socketBaseDtoSet)
                {
                    ArrayList<String> sendDataList=new ArrayList<String>();
                    for (SocketRegisterDto subscribe : s.getSubscribes()) {
                        String stcd = subscribe.getSTCD();
                        ArrayList<String> itemIDs = subscribe.getItemIDs();
                        if (itemIDs != null && itemIDs.size() > 0) {
                            for (String itemID : itemIDs) {
                                String tempKey = getPushDataKey(DevSignalController.pushDataKey, stcd, itemID);
                                for (String key : setKeys) {
                                    if (key.contains(tempKey) == true) {
                                        Gson gson=new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();
                                        String dataListString = redisTampate.get(key);
                                        ArrayList<YY_DATA_AUTO_Request>  list= gson.fromJson(dataListString,new TypeToken<ArrayList<YY_DATA_AUTO_Request>>(){}.getType());
                                        if(list.size()>0) {
                                            YY_DATA_AUTO_Request data = list.get(list.size() - 1);
                                            String dataJson = GsonUtils.toJson(data);
                                            sendDataList.add(dataJson);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    if(sendDataList.size()>0) {
                        String sessionId = s.getSessionId();
                        String dataJson = GsonUtils.toJson(sendDataList);
                        if (dataJson != null && dataJson.length() > 0) {
                            SendMessage(sessionId, dataJson);
                        }
                    }
                }
            }
        } catch (Exception ex) {

        }
    }

    /**
     * 判定session 是否存在
     * @param sessionId
     * @return  true or false
     */
    public boolean existSessionBySessionID(String  sessionId)
    {
        boolean result=false;
        for (SocketBaseDto s : socketBaseDtoSet) {
            if (s.getSessionId().equals(sessionId)) {
                result=true;
                break;
            }
        }
        return result;
    }


    /**
     * 判定session是否存在
     * @param userID
     * @return  true or false
     */
    public boolean existSessionByUserId(String  userID)
    {
        boolean result=false;
        for (SocketMultipleRegisterDto s : socketBaseDtoSet) {
            if (s.getSessionId().equals(userID)) {
                result=true;
                break;
            }
        }
        return result;
    }


    /**
     * 根据用户ID获取SessionId
     * @param userID
     * @return sessionId
     */
    public static String getSessionidByUserID(String userID)
    {
        String  sessionId=null;
        for (SocketMultipleRegisterDto s : socketBaseDtoSet) {
            if (s.getUserID().equals(userID)) {
                sessionId=s.getSessionId();
                break;
            }
        }
        return sessionId;
    }

    /**
     * 根据 SessionId移除socketBaseDtoSet中的数据
     * @param sessionId
     */
    public void removeSessionBySessionId(String sessionId)
    {
        for (SocketMultipleRegisterDto s : socketBaseDtoSet) {
            if (s.getSessionId().equals(sessionId)) {
                socketBaseDtoSet.remove(s);
                break;
            }
        }
    }

    /**
     * 根据 UserId移除socketBaseDtoSet中的数据
     * @param userID
     */
    public void removeSessionByUserID(String userID)
    {
        for (SocketMultipleRegisterDto s : socketBaseDtoSet) {
            if (s.getUserID().equals(userID)) {
                socketBaseDtoSet.remove(s);
                break;
            }
        }

    }


    /**
     * 设置 push数据的key名称
     * @param tag
     * @param stcd
     * @param itemID
     * @return
     */
    public static String getPushDataKey(String tag,String stcd,String itemID)
    {
        return tag+"_"+stcd+"_"+itemID;
    }

    public static CopyOnWriteArraySet<SocketMultipleRegisterDto> getClientSocketBaseDto(){
           return socketBaseDtoSet;
    }
}
